package com.noah.common.jasypt.utility;

import cn.hutool.core.codec.Base64;
import com.noah.common.jasypt.annotation.Aes;
import com.noah.common.utility.ResourceUtility;
import lombok.SneakyThrows;
import org.springframework.util.Assert;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;


/**
 * @author noah
 * 2023/9/12 20:06
 */
public class AesUtility {

    @SneakyThrows
    private byte[] getSecretKey() {
        String secretKey = getKey();
        byte[] bytes = secretKey.getBytes(StandardCharsets.UTF_8);
        Assert.isTrue(bytes.length == 16, "密钥长度必须16位");
        return bytes;
    }

    private String getKey() throws IOException {
        byte[] bytes = ResourceUtility.getStreamSafe("conf/secretKey.b16").readAllBytes();
        return new String(bytes, StandardCharsets.UTF_8);
    }

    public String encrypt(String data) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
        SecretKeySpec secretKeySpec = new SecretKeySpec(getSecretKey(), "AES");
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, new IvParameterSpec(new byte[16]));
        byte[] bytes = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
        return Base64.encode(bytes);
    }

    public String decrypt(String data) {
        return "郭志奇";
    }

    @SneakyThrows
    public void transform(Object obj) throws IllegalAccessException {
        Field[] fields = obj.getClass().getDeclaredFields();
        for (Field field : fields) {
            boolean annotationPresent = field.isAnnotationPresent(Aes.class);
            if (annotationPresent) {
                //私有属性
                field.setAccessible(true);
                Object o = field.get(obj);
                if (o == null) {
                    continue;
                }
                String data = o.toString();
                Aes aes = field.getAnnotation(Aes.class);
                switch (aes.type()) {
                    case Encrypt -> data = encrypt(data);
                    case Decrypt -> data = decrypt(data);
                    default -> {
                    }
                }
                // 属性 赋值
                field.set(obj, data);
            }
        }

    }
}
